package com.wctj.api.infra.common.util.sign;

import com.wctj.api.base.utils.JacksonUtil;
import com.wctj.api.base.utils.JsonUtils;
import com.wctj.api.infra.common.util.str.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.json.JSONObject;

import java.util.*;

import static com.wctj.api.infra.common.util.str.StringUtils.getContentBytes;

/**
* @Description: MD5 验签工具类
* @Param: 
* @return:
* @Author: myl
* @Date: 2024/9/26
*/
@Slf4j
public final class SignMd5Utils {

    /**
    * @Description: 生成签名
    * @Param: [parameters, key, characterEncoding]  parameters 请求入参集合   key 密钥    characterEncoding字符编码
    * @return: java.lang.String
    * @Author: lydms
    * @Date: 2024/9/26
    */
    public String createSign(Map parameters, String key, String characterEncoding) {
        String content = parameterText(parameters);
        return sign(content, key, characterEncoding);
    }

    /**
     * 签名进行验签操作
     * @param parameters        请求入参集合
     * @param sign              签名结果
     * @param key               密钥
     * @param characterEncoding 编码格式
     * @return
     */
    public boolean verify(Map parameters, String sign, String key, String characterEncoding) {
        String text = parameterText(parameters);
        return verify(text, sign, key, characterEncoding);
    }


    /**
     * 签名字符串
     *
     * @param text          需要签名的字符串
     * @param key           密钥
     * @param inputCharset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String inputCharset) {
        //拼接key
        text = text + key;
        log.info("请求入参生成签名:====================="+DigestUtils.md5Hex(getContentBytes(text, inputCharset)));
        return DigestUtils.md5Hex(getContentBytes(text, inputCharset));
    }

    /**
     * 签名字符串
     *
     * @param text          需要签名的字符串
     * @param sign          签名结果
     * @param key           密钥
     * @param inputCharset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String key, String inputCharset) {
        //判断是否一样
        return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
     * @param parameters 参数
     * @return 去掉空值与签名参数后的新签名，拼接后字符串
     */
    public static String parameterText(Map parameters) {
        return parameterText(parameters, "&");
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
     * @param parameters 参数
     * @param separator  分隔符
     * @return 去掉空值与签名参数后的新签名，拼接后字符串
     */
    public static String parameterText(Map parameters, String separator) {
        return parameterText(parameters, separator, "signature", "sign", "key", "sign_type");
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
     * @param parameters 参数
     * @param separator  分隔符
     * @param ignoreKey  需要忽略添加的key
     * @return 去掉空值与签名参数后的新签名，拼接后字符串
     */
    public static String parameterText(Map<String, Object> parameters, String separator, String... ignoreKey) {
        return parameterText(parameters, separator, true, ignoreKey);
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
     * @param parameters      参数
     * @param separator       分隔符
     * @param ignoreNullValue 需要忽略NULL值
     * @param ignoreKey       需要忽略添加的key
     * @return 去掉空值与签名参数后的新签名，拼接后字符串
     */
    public static String parameterText(Map<String, Object> parameters, String separator, boolean ignoreNullValue, String... ignoreKey) {
        if (parameters == null) {
            return "";
        }
        if (null != ignoreKey) {
            Arrays.sort(ignoreKey);
        }
        StringBuffer sb = new StringBuffer();
        if (parameters instanceof SortedMap) {
            for (Map.Entry<String, Object> entry : parameters.entrySet()) {
                Object v = entry.getValue();
                if (null == v) {
                    continue;
                }
                String valStr = v.toString().trim();
                if ("".equals(valStr) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, entry.getKey()) >= 0)) {
                    continue;
                }
                sb.append(entry.getKey()).append("=").append(valStr).append(separator);
            }
            if (sb.length() > 0 && !"".equals(separator)) {
                sb.deleteCharAt(sb.length() - 1);
            }
            return sb.toString();
        }
        return sortMapParameterText(parameters, separator, ignoreNullValue, ignoreKey);
    }

    private static String sortMapParameterText(Map<String, Object> parameters, String separator, boolean ignoreNullValue, String... ignoreKey) {
        StringBuffer sb = new StringBuffer();
        List<String> keys = new ArrayList<String>(parameters.keySet());
        //排序
        Collections.sort(keys);
        for (String k : keys) {
            String valueStr = "";
            Object o = parameters.get(k);
            if (ignoreNullValue && null == o) {
                continue;
            }
            if (o instanceof String[]) {
                String[] values = (String[]) o;

                for (int i = 0; i < values.length; i++) {
                    String value = values[i].trim();
                    if ("".equals(value)) {
                        continue;
                    }
                    valueStr += (i == values.length - 1) ? value : value + ",";
                }
            }
            else {
                valueStr = o.toString();
            }
            if (StringUtils.isBlank(valueStr) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, k) >= 0)) {
                continue;
            }
            sb.append(k).append("=").append(valueStr).append(separator);
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    public static void main(String[] args) {

        /*String aa= "{\n" +
                "\"mid\":\"75\",\n" +
                "\"sign\":\"128964530610007\"\n" +
                "}";*/
        /*String aa= "{\n" +
                "\"subAccount\":\"9022653\",\n" +
                "\"sign\":\"ec6b6a9e10b0131d5a33b8a3a58560c4\"\n" +
                "}";*/

        String aa = "{\"code\":\"3000\",\"msg\":\"招行支付\",\"mid\":\"12345\",\"systemPlatform\":\"letuu\",\"notifyUrl\":\"https://a.zgzgmall.cn/notify.php\",\"sign\":\"daf7dc7276b57241c984a1e35fa370d4\"}";

        JSONObject jsonObject = JsonUtils.convertValue(aa,JSONObject.class);
        //JSONObject jsonObject = JacksonUtil.parse(aa, JSONObject.class);
        //JSONObject jsonObject = JsonUtils.convertValue(aa, JSONObject.class);
        //ObjectMapper mapper = new ObjectMapper();
        //JSONObject jsonObject = mapper.convertValue(aa, JSONObject.class);

        String aaSing =jsonObject.optString("sign");

        //把json对象转换成map对象
        Map map1 = JacksonUtil.parse(aa, Map.class);
        String key = "UVIUODIBDU708";
        String UTF_8 = "UTF-8";
        String s = SignTextUtils.parameterText(map1);
        //System.out.println(s);

        SignMd5Utils signMd5Utils = new SignMd5Utils();
        String sign1 = signMd5Utils.createSign(map1, key, UTF_8);
        //System.out.println(sign1);
        boolean verify1 = signMd5Utils.verify(map1,aaSing,key, UTF_8);
        //System.out.println(verify1);
    }

}
